#ifndef __WIZ_ALGEBRA_VECTOR_HPP__SHANHAOBO_19800429__
#define __WIZ_ALGEBRA_VECTOR_HPP__SHANHAOBO_19800429__

#include "../../Utils/WizAlgebraUtils.hpp"
#include "./WizAlgebraVectorCore.hpp"

namespace Wiz
{
    namespace Vector
    {
        template<class ElementT, int Num>
        struct Type : public ::Wiz::Vector::Core::Type<ElementT, Num>
        {
            WIZ_DECLARE_CLASS_THIS(Type);
            typedef ::Wiz::Vector::Core::Type<ElementT, Num>  tSuper;
            ////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////
            Type()
            {}
            Type(const tElement& InEle) : tSuper(InEle)
            {}
            Type(const tSuper& InOther) : tSuper(InOther)
            {}
            ////////////////////////////////////////////////////////////////////
            WIZ_INLINE tThis& operator=(const tElement& InEle)
            {
                ::Wiz::Int::Type i;
                for (i = 0; i < eCount; i++)
                {
                    this->e[i] = InEle;
                }

                return *this;
            }
            WIZ_INLINE tThis& operator=(const tSuper& InVec)
            {
                ::Wiz::Int::Type i;
                for (i = 0; i < eCount; i++)
                {
                    this->e[i] = InVec.e[i];
                }

                return *this;
            }
            WIZ_INLINE tThis& operator=(tThisIn InVec)
            {
                ::Wiz::Int::Type i;
                for (i = 0; i < eCount; i++)
                {
                    this->e[i] = InVec.e[i];
                }

                return *this;
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement& operator[](::Wiz::UInt::In i)
            {
                WIZ_ASSERT(i < eCount);
                return this->e[i];
            }
            WIZ_INLINE const tElement& operator[](::Wiz::UInt::In i) const
            {
                WIZ_ASSERT(i < eCount);
                return this->e[i];
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE friend tThis& operator +(tThisIn InVec1, tThisIn InVec2)
            {
                tThis OutVec;

                return StaticMethod::Add(OutVec, InVec1, InVec2);
            }
            WIZ_INLINE friend tThis operator +(tThisIn InVec, const tElement& InEle)
            {
                tThis OutVec;

                return StaticMethod::Add(OutVec, InVec, InEle);
            }
            WIZ_INLINE friend tThis operator +(const tElement& InEle, tThisIn InVec)
            {
                tThis OutVec;

                return StaticMethod::Add(OutVec, InVec, InEle);
            }

            WIZ_INLINE friend tThis& operator +=(tThis& InOutVec, const tElement& InEle)
            {
                return StaticMethod::AddAssign(InOutVec, InEle);
            }
            WIZ_INLINE friend tThis& operator +=(tThis& InOutVec, tThisIn InVec)
            {
                return StaticMethod::AddAssign(InOutVec, InVec);
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE friend tThis& operator -(tThisIn InVec1, tThisIn InVec2)
            {
                tThis OutVec;

                return StaticMethod::Subtract(OutVec, InVec1, InVec2);
            }
            WIZ_INLINE friend tThis operator -(tThisIn InVec, const tElement& InEle)
            {
                tThis OutVec;

                return StaticMethod::Subtract(OutVec, InVec, InEle);
            }

            WIZ_INLINE friend tThis& operator -=(tThis& InOutVec, const tElement& InEle)
            {
                return StaticMethod::SubtractAssign(InOutVec, InEle);
            }
            WIZ_INLINE friend tThis& operator -=(tThis& InOutVec, tThisIn InVec)
            {
                return StaticMethod::SubtractAssign(InOutVec, InVec);
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE friend tThis operator*(tThisIn InVec1, tThisIn InVec2)
            {
                tThis OutVec;
                StaticMethod::Multiply(OutVec, InVec1, InVec2);
                return OutVec;
            }
            WIZ_INLINE friend tThis operator*(tThisIn InVec, const tElement& InEle)
            {
                tThis OutVec;
                StaticMethod::Multiply(OutVec, InVec, InEle);

                return OutVec;
            }
            WIZ_INLINE friend tThis operator*(const tElement& InEle, tThisIn InVec)
            {
                tThis OutVec;
                StaticMethod::Multiply(OutVec, InVec, InEle);

                return OutVec;
            }

            WIZ_INLINE friend tThis& operator *=(tThis& InOutVec, const tElement& InEle)
            {
                return StaticMethod::MultiplyAssign(InOutVec, InEle);
            }
            WIZ_INLINE friend tThis& operator *=(tThis& InOutVec, tThisIn InVec)
            {
                return StaticMethod::MultiplyAssign(InOutVec, InVec);
            }
            ////////////////////////////////////////////////////////////////


            ////////////////////////////////////////////////////////////////
            WIZ_INLINE friend tThis& operator/(tThisIn InVec1, tThisIn InVec2)
            {
                tThis OutVec;

                return StaticMethod::Divide(OutVec, InVec1, InVec2);
            }
            WIZ_INLINE friend tThis operator/(tThisIn InVec, const tElement& InEle)
            {
                tThis OutVec;

                return StaticMethod::Divide(OutVec, InVec, InEle);
            }

            WIZ_INLINE friend tThis& operator/=(tThis& InOutVec, const tElement& InEle)
            {
                return StaticMethod::DivideAssign(InOutVec, InEle);
            }
            WIZ_INLINE friend tThis& operator/=(tThis& InOutVec, tThisIn InVec)
            {
                return StaticMethod::DivideAssign(InOutVec, InVec);
            }
            ////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE ::Wiz::Bool::Type operator==(tThisIn InVec) const
            {
                return StaticMethod::IsEqual(*this, InVec);
            }

            WIZ_INLINE ::Wiz::Bool::Type operator!=(tThisIn InVec) const
            {
                return !this->operator==(InVec);
            }

            WIZ_INLINE tThisIn operator+() const
            {
                return *this;
            }

            WIZ_INLINE tThis operator-() const
            {
                tThis OutVec;
                ::Wiz::Int::Type i;
                for (i = 0; i < eCount; i++)
                {
                    OutVec.e[i] = -this->e[i];
                }
                return OutVec;
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement Dot(tThisIn InVec) const
            {
                return StaticMethod::Dot(*this, InVec);
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement AbsDot(tThisIn InVec) const
            {
                return StaticMethod::AbsDot(*this, InVec);
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement Normalize()
            {
                return StaticMethod::Normalize(*this);
            }
            ////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement SqrLength() const
            {
                return StaticMethod::SqrLength(*this);
            }
            //////////////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement Length() const
            {
                return StaticMethod::Length(*this);
            }
            //////////////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement RecipLength() const
            {
                return StaticMethod::RecipLength(*this);
            }
            //////////////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement Distance(tThisIn InVec) const
            {
                return StaticMethod::Distance(*this, InVec);
            }
            ////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////
            WIZ_INLINE tElement SqrDistance(tThisIn InVec) const
            {
                return StaticMethod::SqrDistance(*this, InVec);
            }
            ////////////////////////////////////////////////////////////////
        }; /// end of struct Type
    } /// end of namespace Vector
} /// end of namespace Wiz

#endif /*__WIZ_ALGEBRA_VECTOR_HPP__SHANHAOBO_19800429__*/
